import networkx as nx
import ast

from EmpVoting.Model import Agent
from EmpVoting.Model import EmpNetwork

class GenFromFile(object):

    def __init__(self, path, networkFormat, additionalGenList):
        '''
        Constructor
        '''
        self.Path = path
        self.Format = networkFormat
        self.AdditionalGenList = additionalGenList
        

    def Generate(self):

        network = EmpNetwork()
        
        if self.Format == "gexf":
            network.graph = nx.read_gexf(self.Path, relabel=False, version="1.1")
            self._InitializeNetworkFromXmlGraph(network)
            
        elif self.Format == "graphml":
            network.graph = nx.read_graphml(self.Path)
            self._InitializeNetworkFromXmlGraph(network)
                
        elif self.Format == "gpickle":
            network.graph = nx.read_gpickle(self.Path)
            self._InitializeNetworkFromBinaryGraph(network)
            
        else:
            print("Error: Unknown network format.")
            return
        
        for generator in self.AdditionalGenList:
            generator.Apply(network)  
        
        return network
        
    def _InitializeNetworkFromBinaryGraph(self, network):
        self._InitializeNetworkFields(network)
        
        network.agentList = network.graph.nodes()
        
    def _InitializeNetworkFromXmlGraph(self, network):
        self._InitializeNetworkFields(network)
        
        network.agentList = []
        
        for agentId in network.graph.nodes():
            #Remove "Id:" from the id
            agent = Agent(agentId[3:])
            
            for fieldName, value in network.graph.node[agentId].items():
                agent.__dict__[fieldName] = self._GetValueFromSerializedState(value)
            network.agentList.append(agent)
            self._ReplaceNode(network.graph, agentId, agent)
            
          
    
    def _InitializeNetworkFields(self, network):
        for fieldName, value in network.graph.graph.items():
            if fieldName == "edge_default" or fieldName == "node_default":
                continue
            
            network.__dict__[fieldName] = self._GetValueFromSerializedState(value)
    
    def _GetValueFromSerializedState(self, value):
        if isinstance(value, unicode) or isinstance(value, str):
            if isinstance(value, unicode):
                value = value.encode('utf-8')

            try:
                if value.startswith("set("):
                    value = ast.literal_eval(value[len("set("):-1])
                    value = set(value)
                else:
                    value = ast.literal_eval(value)     
            except:
                pass

        return value
    
    def _ReplaceNode(self, graph, oldNode, newNode):
        graph.add_node(newNode)
        
        for sourceNode in graph.predecessors(oldNode):
            graph.add_edge(sourceNode, newNode, attr_dict=graph[sourceNode][oldNode])
        
        for targetNode in graph.successors(oldNode):
            graph.add_edge(newNode, targetNode, attr_dict=graph[oldNode][targetNode])
            
        graph.remove_node(oldNode)